package org.dromara.common.core.utils.reflect;

import cn.hutool.core.util.ReflectUtil;
import org.dromara.common.core.utils.StringUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;

import java.lang.reflect.Method;


/**
 * @Author 刘武贵
 * @Date 2024/8/15 22:00
 * @Description 功能描述：射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数.
 */
@SuppressWarnings("rawtypes")
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ReflectUtils extends ReflectUtil {

    /**
     * 定义属性设置方法的前缀
     */
    private static final String SETTER_PREFIX = "set";

    /**
     * 定义属性获取方法的前缀
     */
    private static final String GETTER_PREFIX = "get";

    /**
     * 调用Getter方法.
     * 支持多级，如：对象名.对象名.方法
     * 调用对象的getter方法来获取属性值
     * 这个方法支持访问嵌套属性，通过传递包含多个层级的propertyName
     * 例如，传递"address.city"可以获取到嵌套属性"address"的"city"属性
     *
     * @param obj 要访问的对象
     * @param propertyName 属性名，支持多级嵌套
     * @param <E> 返回类型
     * @return 属性值
     */
    @SuppressWarnings("unchecked")
    public static <E> E invokeGetter(Object obj, String propertyName) {
        // 初始化对象为传入的参数对象
        Object object = obj;
        // 分割属性名，处理多级嵌套
        for (String name : StringUtils.split(propertyName, ".")) {
            // 构造getter方法名 获取方法的前缀 + 属性名首字母大写
            String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name);
            // 调用对象的getter方法，更新object为当前属性的值
            object = invoke(object, getterMethodName);
        }
        return (E) object;
    }

    /**
     * 调用Setter方法, 仅匹配方法名。
     * 支持多级，如：对象名.对象名.方法
     * 调用对象的setter方法设置属性值
     *
     * @param obj 要设置属性值的对象
     * @param propertyName 属性名，支持多级属性（使用.分隔）
     * @param value 要设置的属性值
     * @param <E> 泛型参数，表示属性值的类型
     */
    public static <E> void invokeSetter(Object obj, String propertyName, E value) {
        // 将对象转换为Object类型，以便在方法内部进行操作
        Object object = obj;
        // 使用StringUtils.split方法根据"."分割propertyName，获取属性名数组
        String[] names = StringUtils.split(propertyName, ".");
        // 遍历属性名数组
        for (int i = 0; i < names.length; i++) {
            // 如果不是最后一个属性名
            if (i < names.length - 1) {
                // 构造getter方法名，用于获取嵌套对象 属性设置方法的前缀 + 属性名首字母大写
                String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]);
                // 调用invoke方法，获取嵌套对象
                object = invoke(object, getterMethodName);
            } else {
                // 构造setter方法名，用于设置属性值
                String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
                // 根据方法名获取Method对象 属性获取方法的前缀 + 属性名首字母大写
                Method method = getMethodByName(object.getClass(), setterMethodName);
                // 调用invoke方法，设置属性值
                invoke(object, method, value);
            }
        }
    }

}
